#include "imageprocessor.h"
#include <QDebug>

ImageProcessor::ImageProcessor(OpenCLManager *oclManager, QObject *parent)
    : QObject(parent), m_oclManager(oclManager)
{
    if(!initializeProgram()) {
        qWarning() << "Failed to initialize OpenCL program";
    }
}

bool ImageProcessor::initializeProgram()
{
    if(!m_oclManager || !m_oclManager->initialize()) {
        return false;
    }

    const char *kernelSource = R"(
        __kernel void grayscale(
            __read_only image2d_t input,
            __write_only image2d_t output,
            sampler_t sampler)
        {
            int2 coord = (int2)(get_global_id(0), get_global_id(1));
            float4 pixel = read_imagef(input, sampler, coord);
            float gray = 0.299f * pixel.x + 0.587f * pixel.y + 0.114f * pixel.z;
            write_imagef(output, coord, (float4)(gray, gray, gray, 1.0f));
        }
    )";

    try {
        cl::Program::Sources sources;
        sources.push_back({kernelSource, strlen(kernelSource)});

        m_program = cl::Program(m_oclManager->context(), sources);
        m_program.build({m_oclManager->device()});

        m_initialized = true;
        return true;

    } catch (const cl::Error &err) {
        qCritical() << "OpenCL program build error:" << err.what();
        if(err.err() == CL_BUILD_PROGRAM_FAILURE) {
            std::string buildLog = m_program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(m_oclManager->device());
            qCritical() << "Build log:" << buildLog.c_str();
        }
        return false;
    }
}

QImage ImageProcessor::processImage(const QImage &input)
{
    if(!m_initialized || input.isNull()) {
        return input;
    }

    try {
        // 转换图像格式为RGBA8888
        QImage image = input.convertToFormat(QImage::Format_RGBA8888);
 
        // 创建OpenCL图像格式
        cl::ImageFormat format(CL_RGBA, CL_UNORM_INT8);

        // 创建输入输出图像对象
        cl::Image2D clInput(
            m_oclManager->context(),
            CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
            format,
            image.width(),
            image.height(),
            0,
            (void*)image.constBits());

        cl::Image2D clOutput(
            m_oclManager->context(),
            CL_MEM_WRITE_ONLY,
            format,
            image.width(),
            image.height());

        // 创建采样器
        cl::Sampler sampler(
            m_oclManager->context(),
            CL_FALSE,
            CL_ADDRESS_CLAMP_TO_EDGE,
            CL_FILTER_NEAREST);

        // 创建内核并设置参数
        cl::Kernel kernel(m_program, "grayscale");
        kernel.setArg(0, clInput);
        kernel.setArg(1, clOutput);
        kernel.setArg(2, sampler);

        // 执行内核
        cl::NDRange globalSize(image.width(), image.height());
        m_oclManager->queue().enqueueNDRangeKernel(
            kernel,
            cl::NullRange,
            globalSize,
            cl::NullRange);

        // 读取结果
        cl::size_t<3> orgin, region;
        orgin[0] = 0;
        orgin[1] = 0;
        orgin[2] = 0;
        region[0] = image.width();
        region[1] = image.height();
        region[2] = 1;
        QImage result(image.size(), image.format());
        m_oclManager->queue().enqueueReadImage(
            clOutput,
            CL_TRUE,
            orgin,
            region,
            0, 0,
            result.bits());

        return result;

    } catch (const cl::Error &err) {
        qCritical() << "OpenCL processing error:" << err.what() << "(" << err.err() << ")";
        return input;
    }
}
